import { Middleware, IMiddleware, Config, Inject } from '@midwayjs/core';
import { NextFunction, Context } from '@midwayjs/koa';
import { JwtService } from '@midwayjs/jwt';

@Middleware()
export class AuthMiddleware implements IMiddleware<Context, NextFunction> {
  @Config('cookies.tokenKey')
  private tokenKey: string;

  @Config('apiKeyWordWhiteList')
  private apiKeyWordWhiteList: string[];

  @Inject()
  private jwtService: JwtService;

  resolve() {
    return async (ctx: Context, next: NextFunction) => {
      // 白名单接口不校验 token
      if (this.apiKeyWordWhiteList.some(item => ctx.path.includes(item))) {
        await next();
      } else {
        const cookieToken = ctx.cookies.get(this.tokenKey);

        let headerToken = ctx.headers[this.tokenKey];
        if (Array.isArray(headerToken)) {
          headerToken = headerToken[0];
        }

        let authToken = ctx.headers.authorization;
        if (authToken && authToken.startsWith('Bearer ')) {
          authToken = authToken.slice(7);
        }

        // 统一获取 token，优先级可调整
        const token = authToken || headerToken || cookieToken;
        if (!token) {
          // 需要清理cookie中的token
          ctx.cookies.set(this.tokenKey, '', {
            httpOnly: true,
            secure: ctx.secure,
            sameSite: 'strict'
          });
          ctx.status = 401;
          ctx.body = {
            code: 401,
            success: false,
            timestamp: Date.now(),
            data: null,
            message: '未登录'
          };
        } else {
          try {
            await this.jwtService.verify(token.trim());
            await next();
          } catch (error) {
            ctx.status = ctx.response.status;
            if (error.message.indexOf('jwt expired') !== -1) {
              ctx.status = 401;
              ctx.cookies.set(this.tokenKey, '', {
                httpOnly: true,
                secure: ctx.secure,
                sameSite: 'strict'
              });
            }
            ctx.body = {
              code: ctx.response.status,
              success: false,
              timestamp: Date.now(),
              data: null,
              message: error.message
            };
          }
        }
      }
    };
  }

  static getName(): string {
    return 'auth';
  }
}
